//const readline = require("readline");
//const rl = readline.createInterface({
//    input: process.stdin,
//    output: process.stdout
//});
//let n;
//let initArr = [];
//rl.on("line", (line)=>{
//
//})

const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// **最小堆（优先队列）**
class MinHeap {
    constructor() {
        this.heap = [];
    }

    push(node) {
        this.heap.push(node);
        let i = this.heap.length - 1;
        while (i > 0 && this.heap[i].time < this.heap[Math.floor((i - 1) / 2)].time) {
            [this.heap[i], this.heap[Math.floor((i - 1) / 2)]] =
                [this.heap[Math.floor((i - 1) / 2)], this.heap[i]];
            i = Math.floor((i - 1) / 2);
        }
    }

    pop() {
        if (this.heap.length === 0) return null;
        const top = this.heap[0];
        const last = this.heap.pop();
        if (this.heap.length > 0) {
            this.heap[0] = last;
            let i = 0, j = 2 * i + 1;
            while (j < this.heap.length) {
                if (j + 1 < this.heap.length && this.heap[j + 1].time < this.heap[j].time) j++;
                if (this.heap[j].time >= this.heap[i].time) break;
                [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
                i = j;
                j = 2 * i + 1;
            }
        }
        return top;
    }

    size() {
        return this.heap.length;
    }
}

let n, m;
const matrix = [];
const positions = {}; // 记录相同值的坐标

rl.on("line", (line) => {
    if (!n) {
        [n, m] = line.split(" ").map(Number);
    } else {
        const row = line.split(" ").map(Number);
        matrix.push(row);
        for (let j = 0; j < m; j++) {
            if (!positions[row[j]]) positions[row[j]] = [];
            positions[row[j]].push([matrix.length - 1, j]);
        }
    }
}).on("close", () => {
    const INF = Number.MAX_SAFE_INTEGER;

    // **存储最短路径时间**
    const normalTime = new Map();  // 记录普通路径的最短时间
    const portalTime = new Map();  // 记录传送路径的最短时间
    let pq = new MinHeap();

    // **初始化起点**
    normalTime.set("0,0", 0);
    pq.push({time: 0, x: 0, y: 0, usedPortal: false});

    const directions = [
        [1, 0], [-1, 0], [0, 1], [0, -1]
    ];

    while (pq.size() > 0) {
        let {time, x, y, usedPortal} = pq.pop();
        let key = `${x},${y}`;

        // **如果当前路径时间已经不是最短，跳过**
        if ((usedPortal && portalTime.get(key) !== time) || (!usedPortal && normalTime.get(key) !== time)) {
            continue;
        }

        // **普通移动（上下左右）**
        for (let [dx, dy] of directions) {
            let nx = x + dx, ny = y + dy;
            if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                let newTime = time + Math.abs(matrix[x][y] - matrix[nx][ny]);
                let nextKey = `${nx},${ny}`;
                let currTime = usedPortal ? portalTime.get(nextKey) : normalTime.get(nextKey);

                if (currTime === undefined || newTime < currTime) {
                    if (usedPortal) {
                        portalTime.set(nextKey, newTime);
                    } else {
                        normalTime.set(nextKey, newTime);
                    }
                    pq.push({time: newTime, x: nx, y: ny, usedPortal});
                }
            }
        }

        // **传送阵（跳跃到相同值的位置）**
        if (!usedPortal) {
            for (let [nx, ny] of positions[matrix[x][y]]) {
                let nextKey = `${nx},${ny}`;
                if (portalTime.get(nextKey) === undefined || time < portalTime.get(nextKey)) {
                    portalTime.set(nextKey, time);
                    pq.push({time, x: nx, y: ny, usedPortal: true});
                }
            }
        }
    }

    // **获取最短时间**
    let endKey = `${n - 1},${m - 1}`;
    let result = Math.min(
        normalTime.get(endKey) ?? INF,
        portalTime.get(endKey) ?? INF
    );

    console.log(result);
});
